﻿using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.Linq;

//------------------------------------------------------------
// shaco Framework
// Copyright © 2017-2021 chang.liu All rights reserved.
// Feedback: 449612236@qq.com
//------------------------------------------------------------

namespace shacoEditor
{
    public class ChangeMeshReadableHelper
    {
        [MenuItem("Assets/shaco/Mesh/Readable(On)", false)]
        static void GUI_On()
        {
            foreach (var iter in GetSelectMeshs())
            {
                ChangeMeshReadable(iter, true);
            }
        }

        [MenuItem("Assets/shaco/Mesh/Readable(On)", true)]
        static bool GUIValid_On()
        {
            return GUIValid();
        }

        [MenuItem("Assets/shaco/Mesh/Readable(Off)", false)]
        static void GUI_Off()
        {
            foreach (var iter in GetSelectMeshs())
            {
                ChangeMeshReadable(iter, false);
            }
        }

        [MenuItem("Assets/shaco/Mesh/Readable(Off)", true)]
        static bool GUIValid_Off()
        {
            return GUIValid();
        }

        [MenuItem("GameObject/shaco/Mesh/Readable(On)", false)]
        static void GameObject_On()
        {
            GameObject_Set(v => ChangeMeshReadable(v, true));
        }

        [MenuItem("GameObject/shaco/Mesh/Readable(On)", true)]
        static bool GameObjectValid_On()
        {
            return Selection.gameObjects.Any(v => v.GetComponent<MeshFilter>() || v.GetComponent<SkinnedMeshRenderer>());
        }

        [MenuItem("GameObject/shaco/Mesh/Readable(Off)", false)]
        static void GameObject_Off()
        {
            GameObject_Set(v => ChangeMeshReadable(v, false));
        }

        [MenuItem("GameObject/shaco/Mesh/Readable(Off)", true)]
        static bool GameObjectValid_Off()
        {
            return Selection.gameObjects.Any(v => v.GetComponent<MeshFilter>() || v.GetComponent<SkinnedMeshRenderer>());
        }

        static bool GUIValid()
        {
            return Selection.objects.Any(v =>
            {
                var extension = System.IO.Path.GetExtension(AssetDatabase.GetAssetPath(v)).ToLower();
                if (extension == ".fbx" || extension == ".mesh" || extension == ".asset")
                    return true;
                return false;
            });
        }

        static IEnumerable<Mesh> GetSelectMeshs()
        {
            var retValue = new Queue<Mesh>();
            foreach (var iter in Selection.objects)
            {
                var assetPath = AssetDatabase.GetAssetPath(iter);
                var extension = System.IO.Path.GetExtension(assetPath).ToLower();
                Mesh meshTest = null;
                if (extension == ".fbx")
                {
                    meshTest = AssetDatabase.LoadAssetAtPath<Mesh>(assetPath);
                }
                else if (extension == ".mesh" || extension == ".asset")
                {
                    meshTest = iter as Mesh;
                }

                if (null != meshTest)
                    retValue.Enqueue(meshTest);
            }
            return retValue;
        }

        static void GameObject_Set(System.Action<Mesh> callbackSet)
        {
            var meshfilters = Selection.gameObjects.Select(v => v.GetComponent<MeshFilter>());
            var skinRenders = Selection.gameObjects.Select(v => v.GetComponent<SkinnedMeshRenderer>());

            foreach (var iter in meshfilters)
            {
                if (null != iter)
                    callbackSet(iter.sharedMesh);
            }
            foreach (var iter in skinRenders)
            {
                if (null != iter)
                    callbackSet(iter.sharedMesh);
            }
        }

        static public bool ChangeMeshReadable(Mesh mesh, bool readable)
        {
            if (null == mesh)
            {
                Debug.LogError("mesh is null");
            }

            var assetPath = AssetDatabase.GetAssetPath(mesh);
            if (string.IsNullOrEmpty(assetPath))
            {
                Debug.LogError("Can't get asset path by mesh=" + mesh, mesh);
                return false;
            }

            //过滤unity内置路径
            if (assetPath.StartsWith("Library/"))
            {
                return true;
            }

            var importer = AssetImporter.GetAtPath(assetPath) as ModelImporter;
            if (null != importer)
            {
                if (importer.isReadable != readable)
                {
                    importer.isReadable = readable;
                    AssetDatabase.ImportAsset(assetPath);
                }
                return true;
            }

            if (!System.IO.File.Exists(assetPath))
            {
                Debug.LogError("ChangeMeshReadable error: not found path=" + assetPath);
                return false;
            }

            // if (!assetPath.EndsWith(".asset") && !assetPath.EndsWith(".mesh"))
            // {
            //     Debug.LogError("Only support mesh source file, path=" + assetPath, mesh);
            //     return false;
            // }

            var readStr = System.IO.File.ReadAllText(assetPath);
            var findTag = "m_IsReadable: ";
            var findIndex = readStr.IndexOf(findTag);

            if (findIndex >= 0)
            {
                var oldReadable = readStr.Substring(findIndex + findTag.Length, 1) == "1";
                if (oldReadable != readable)
                {
                    readStr = readStr.Remove(findIndex + findTag.Length, 1);
                    readStr = readStr.Insert(findIndex + findTag.Length, readable ? "1" : "0");
                    System.IO.File.WriteAllText(assetPath, readStr);
                    AssetDatabase.ImportAsset(assetPath);
                }
                return true;
            }
            else
            {
                Debug.LogError($"Not found tag '{findTag}' in mesh=" + mesh + " path=" + assetPath, mesh);
                return false;
            }
        }
    }
}